package utils.csv;

import com.csvreader.CsvReader;
import com.microsoft.sqlserver.jdbc.StringUtils;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.read.biff.BiffException;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import utils.DateUtils;
import utils.Reflections;
import utils.csv.annotation.CSVField;
import utils.csv.annotation.CsvIngore;
import utils.csv.annotation.CsvProperty;
import utils.csv.reflect.CsvField;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by chen on 17/4/24.
 */
public class CsvUtils {
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 生成csv
     *
     * @param head
     * @param dataList
     * @param path
     * @return
     */
    public static File createCSVFile(List<Object> head, List<List<Object>> dataList, String path) throws IOException {
        File csvFile = new File(path);

        if (!csvFile.exists()) {
            if (!csvFile.getParentFile().exists()) {
                csvFile.getParentFile().mkdir();
            }
            csvFile.createNewFile();
        }
        try (BufferedWriter csvWtriter = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(csvFile), "UTF-8"), 1024)) {
            writeRow(head, csvWtriter);
            for (List<Object> row : dataList) {
                writeRow(row, csvWtriter);
            }
            csvWtriter.flush();
        } catch (IOException e) {
            throw e;
        }
        return csvFile;
    }

    /**
     * 生成csv
     *
     * @param dataList
     * @param path
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> File createCSVFile(List<T> dataList, String path) throws IOException {
        File csvFile = new File(path);
        if (!csvFile.exists()) {
            if (csvFile.getParentFile() != null && !csvFile.getParentFile().exists()) {
                csvFile.getParentFile().mkdirs();
            }
            csvFile.createNewFile();
        }

        if (dataList == null || dataList.size() == 0) {
            throw new IllegalArgumentException("datalist不能为空");
        }
        List<CsvField> csvFields = getFieldList(dataList.get(0).getClass());
        try (BufferedWriter csvWriter = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(csvFile), "GB2312"), 1024)) {
            writeHead(csvFields, csvWriter);
            for (T t : dataList) {
                writeRow(t, csvFields, csvWriter);
            }
            csvWriter.flush();
        } catch (IOException e) {
            throw e;
        }
        return csvFile;
    }


    /**
     * 追加数据到已存在的csv文件中
     *
     * @param dataList
     * @param clazz
     * @param path
     * @param <T>
     * @throws IOException
     */
    public static <T> void appendToCSVFile(List<T> dataList, Class<T> clazz, String path) throws IOException {
        File csvFile = new File(path);
        if (csvFile.exists() && dataList != null && !dataList.isEmpty()) {
            List<CsvField> csvFields = CsvUtils.getFieldList(clazz);
            if (csvFields != null && !csvFields.isEmpty()) {
                try (BufferedWriter csvWriter = new BufferedWriter(
                        new OutputStreamWriter(new FileOutputStream(csvFile, true), "GB2312"), 1024)) {
                    for (T t : dataList) {
                        writeRow(t, csvFields, csvWriter);
                    }
                    csvWriter.flush();
                } catch (IOException e) {
                    throw e;
                }
            }
        }
    }


    /**
     * 导入csv
     *
     * @param file
     * @return
     */
    public static List<String> importCsv(File file) {
        List<String> dataList = new ArrayList<>();
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "GBK"));
            String line = "";
            while ((line = br.readLine()) != null) {
                dataList.add(line);
            }
        } catch (Exception e) {
        } finally {
            if (br != null) {
                try {
                    br.close();
                    br = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return dataList;
    }


    /**
     * 导入excel,只读第一列数据
     *
     * @param file
     * @return
     * @throws IOException
     * @throws BiffException
     */
    public static List<String> importXLS(File file) throws IOException, BiffException {
        List<String> list = new ArrayList<>();
        Workbook wb = Workbook.getWorkbook(file);
        Sheet sheet = wb.getSheet(0);
        int rowNum = sheet.getRows();
        if (rowNum >= 1) {
            for (int r = 0; r < rowNum; r++) {
                Cell cell = sheet.getCell(0, r);//只读取每一行第一列
                String value = cell.getContents();
                if (StringUtils.isEmpty(value)) {
                    continue;
                }
                list.add(value);
            }
        }
        return list;
    }

    /***
     * 根据表头生成MAP数据
     * @param file
     * @return
     * @throws IOException
     * @throws BiffException
     */
    public static List<Map<String, String>> importDynXLS(File file) throws IOException, BiffException {
        List<Map<String, String>> list = new ArrayList<>();
        Workbook wb = Workbook.getWorkbook(file);
        Sheet sheet = wb.getSheet(0);
        int rowNum = sheet.getRows();
        Cell[] headRow = sheet.getRow(0);
        int colNum = headRow.length;
        String[] titleArr = new String[colNum];
        for (int i = 0; i < colNum; i++) {
            titleArr[i] = headRow[i].getContents();
        }
        if (rowNum >= 1) {
            for (int r = 1; r < rowNum; r++) {
                Map<String, String> dataMap = new HashMap<>();
                for (int i = 0; i < colNum; i++) {
                    String content = sheet.getCell(i, r).getContents();
                    dataMap.put(titleArr[i], content == null ? "" : content);
                }
                list.add(dataMap);
            }
        }
        return list;
    }




    /**
     * 写入头部
     *
     * @param csvFields
     * @param csvWriter
     * @throws IOException
     */
    private static void writeHead(List<CsvField> csvFields, BufferedWriter csvWriter) throws IOException {
        for (CsvField csvField : csvFields) {
            String alias = csvField.getField().getAnnotation(CsvProperty.class).alias();
            if (alias == null) {
                alias = csvField.getField().getName();
            }
            StringBuffer sb = new StringBuffer();
            String rowStr = sb.append("\"").append(alias).append("\",").toString();
            csvWriter.write(rowStr);
        }
        csvWriter.newLine();
    }

    private static <T> void writeRow(T t, List<CsvField> csvFields, BufferedWriter csvWriter) throws IOException {
        for (CsvField csvField : csvFields) {
            String datePattern = csvField.getField().getAnnotation(CsvProperty.class).datePattern();
            boolean isAmount = csvField.getField().getAnnotation(CsvProperty.class).isAmount();
            Object value = Reflections.getFieldValue(t, csvField.getField().getName());
            value = value == null ? "" : value;
            if (datePattern != null && !"".equals(datePattern) && value != null && !"".equals(value)) {
                value = DateUtils.formatDate(datePattern,(Date) value);
            }
            if (isAmount == true && value != null && !"".equals(value)) {
                NumberFormat ddf = NumberFormat.getNumberInstance();
                ddf.setMinimumFractionDigits(2);
                value = ddf.format((int) value * 0.01);
            }
            StringBuffer sb = new StringBuffer();
            String rowStr = sb.append("\"").append(value).append("\",").toString();
            csvWriter.write(rowStr);
        }
        csvWriter.newLine();
    }

    private static void writeRow(List<Object> row, BufferedWriter csvWriter) throws IOException {
        // 写入文件头部
        for (Object data : row) {
            StringBuffer sb = new StringBuffer();
            String rowStr = sb.append("\"").append(data).append("\",").toString();
            csvWriter.write(rowStr);
        }
        csvWriter.newLine();
    }

    private static <T> List<CsvField> getFieldList(Class<T> clazz) {
        int defaultOrder = -1;
        List<CsvField> csvFields = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            if (f.getAnnotation(CsvIngore.class) != null && f.getAnnotation(CsvIngore.class).value()) continue;
            if (f.getAnnotation(CsvProperty.class) == null) continue;
            Integer order = 0;
            Boolean notIgnore = false;
            Boolean isAmout = false;
            CsvProperty csvPropertyAnno = f.getAnnotation(CsvProperty.class);
            if (csvPropertyAnno != null) {
                order = csvPropertyAnno.order();
                if (order != null && order < 0)
                    throw new IllegalArgumentException(f.getClass().getName() + "." + f.getName() + "() @CsvProperty order必须大于0");
                if (order == null || order == 0) order = defaultOrder -= 1;
                notIgnore = csvPropertyAnno.notIgnore();
                isAmout = csvPropertyAnno.isAmount();
            } else order = defaultOrder -= 1;
            csvFields.add(new CsvField(order, f, isAmout, notIgnore));
        }
        csvFields.sort((f1, f2) -> f2.getOrder() - f1.getOrder());
        return csvFields;
    }

    public static <T> List<List<Object>> getExportData(List<T> list, List<Object> headList) {
        if (list == null || list.size() < 1 || headList == null || headList.size() < 1) {
            return new ArrayList<>();
        }
        Map<String, String> aliasMap = new HashMap<>();
        Field[] fields = list.get(0).getClass().getDeclaredFields();
        for (Field f : fields) {
            CsvProperty csvProperty = f.getAnnotation(CsvProperty.class);
            if (csvProperty != null && !StringUtils.isEmpty(csvProperty.alias())) {
                aliasMap.put(csvProperty.alias(), f.getName());
            }
        }
        List<List<Object>> dataList = new ArrayList<>();
        for (T t : list) {
            List<Object> rowList = new ArrayList<>();
            for (Object head : headList) {
                if (head.equals("派发时间") || head.equals("实际还款时间") || head.equals("实际催回日期")) {
                    rowList.add(simpleDateFormat.format(Reflections.getFieldValue(t, aliasMap.get(head)) == null ? "" : Reflections.getFieldValue(t, aliasMap.get(head))));
                } else if (head.equals("资产编号")) {
                    rowList.add("'" + (Reflections.getFieldValue(t, aliasMap.get(head)) == null ? "" : Reflections.getFieldValue(t, aliasMap.get(head))));
                } else if (aliasMap.containsKey(head)) {
                    rowList.add(Reflections.getFieldValue(t, aliasMap.get(head)) == null ? "" : Reflections.getFieldValue(t, aliasMap.get(head)));
                } else {
                    rowList.add("");
                }
            }
            dataList.add(rowList);
        }
        return dataList;
    }


    /**
     * 数组标题与值的对应关系
     *
     * @param dataList
     * @return
     */
    private static <T> List<Map<String, String>> getTitles(List<String[]> dataList) {
        List<Map<String, String>> list = new ArrayList<>();
        String[] titles = dataList.get(0);
        dataList.remove(0);
        for (String[] values : dataList) {
            Map<String, String> titleMap = new HashMap<>();
            for (int i = 0; i < values.length; i++) {
                titleMap.put(titles[i], values[i]);
            }
            list.add(titleMap);
        }
        return list;
    }

    /**
     * 注解名称与字段属性的对应关系
     *
     * @param clazz 实体对象类类型
     * @param <T>   泛型类型
     * @return Map<String       ,       Field>
     */
    private static <T> Map<String, Field> getFields(Class<T> clazz) {
        Map<String, Field> annoMap = new HashMap<>();
        Field[] fileds = clazz.getDeclaredFields();
        for (Field filed : fileds) {
            CSVField anno = filed.getAnnotation(CSVField.class);
            if (anno != null) {
                // 获取name属性值
                if (StringUtils.isEmpty(anno.name())) {
                    annoMap.put(anno.name(), filed);
                }
            }
        }
        return annoMap;
    }


    public static void main(String[] args) throws Exception {

        /*File file=new File("/Users/lining/Desktop/工作簿3.xls");
        File pathFile = new File(file.getParent());
        System.out.println(pathFile.isDirectory());
        System.out.println(pathFile.isFile());
        System.out.println(file.getParent());
        System.out.println(file.getPath());*/


        String tempPath = new StringBuilder()
                .append("/Users/lining/Desktop/1/2/5")
                .toString();
        File file = new File(tempPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        System.out.println(file.exists());


    }

}
